package com.fs.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fs.entity.Door;
import com.fs.entity.Switch;
import com.fs.global.config.CustomConfig;
import com.fs.repository.DoorRepository;
import com.fs.repository.SwitchRepository;
import com.fs.service.bo.device.*;
import com.fs.utils.HttpUtils;

import static com.fs.utils.HttpUtils.HttpResult;

import com.google.gson.Gson;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class DeviceOperationService {
    private final DoorRepository doorDao;
    private final SwitchRepository switchDao;
    private final CustomConfig config;
    private List<BoDoor> doors;
    private List<BoSwitch> switches;
    private final String OPEN_DOOR_COMMAND = "1";
    private final String OPEN_SWITCH_COMMAND = "1";
    private final String CLOSE_SWITCH_COMMAND = "0";


    public DeviceOperationService(DoorRepository doorDao, SwitchRepository switchDao, CustomConfig config) {
        this.doorDao = doorDao;
        this.switchDao = switchDao;
        this.config = config;
    }

    @PostConstruct
    void init() {
        List<Door> doorList = doorDao.findAll();
        doors = doorList.stream().map(BoDoor::new).collect(Collectors.toList());

        List<Switch> switchList = switchDao.findAll();
        switches = switchList.stream().map(BoSwitch::new).collect(Collectors.toList());
    }


    public void openDoor(int doorId) throws Exception {
        Optional<BoDoor> first = doors.stream().filter(d -> d.getId() == doorId).findFirst();
        Assert.isTrue(first.isPresent(), "开门异常,没有找到门信息");

        BoDoor door = first.get();
        String command = buildCommand(door.getTypeId(), new String[]{door.getDeviceId()}, DeviceType.Door, OPEN_DOOR_COMMAND);
        String token = requestAccessToken();

        HttpResult httpResult = HttpUtils.postBody(config.getSundrayBaseUrl() + "/device/setStatus?access_token=" + token, command);
        if (httpResult.getStatusCode() != 200) {
            throw new Exception("新瑞平台开门失败");
        }
        Map map = JSON.parseObject(httpResult.getResult(), Map.class);
        boolean success = (boolean) map.get("success");
        if (!success) {
            throw new Exception("新瑞平台开门失败");
        }

    }

    public void openSwitches(List<Integer> switchIds) throws Exception {
        controlSwitch(switchIds, OPEN_SWITCH_COMMAND);
    }


    public void closeSwitches(List<Integer> switchIds) throws Exception {
        controlSwitch(switchIds, CLOSE_SWITCH_COMMAND);
    }

    private void controlSwitch(List<Integer> switchIds, String status) throws Exception {
        List<BoSwitch> list = switches.stream().filter(d -> switchIds.contains(d.getId())).collect(Collectors.toList());
        Assert.isTrue(list.size() > 0, "初始化空开信息有问题");

        String[] deviceIds = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            deviceIds[i] = list.get(i).getDeviceId();
        }

        String command = buildCommand(list.get(0).getTypeId(), deviceIds, DeviceType.Switch, status);
        String token = requestAccessToken();

        HttpResult httpResult = HttpUtils.postBody(config.getSundrayBaseUrl() + "/device/setStatus?access_token=" + token, command);
        if (httpResult.getStatusCode() != 200) {
            throw new Exception("新瑞平台操作空开失败");
        }
        Map map = JSON.parseObject(httpResult.getResult(), Map.class);
        boolean success = (boolean) map.get("success");
        if (!success) {
            throw new Exception("新瑞平台操作空开失败");
        }
    }

    public BoAllDeviceState getDeviceStatus() throws Exception {

        JSONObject command = new JSONObject();
        HashMap<String, Object> hashMap = new HashMap<String, Object>() {
            {
                put("all", true);
            }
        };
        command.put(config.getSundraySpaceId(), new JSONObject(hashMap));

        String token = requestAccessToken();
        HttpResult httpResult = HttpUtils.postBody(config.getSundrayBaseUrl() + "/device/getStatus?access_token=" + token
                , command.toJSONString());
        if (httpResult.getStatusCode() != 200) {
            throw new Exception("新瑞平台获取设备状态失败");
        }

        JSONObject backInfo = JSON.parseObject(httpResult.getResult());
        if (!backInfo.getBoolean("success")) {
            throw new Exception("新瑞平台获取设备状态失败");
        }
        JSONObject topLevel = backInfo.getJSONObject(config.getSundraySpaceId());

        List<BoDoorWithState> doorStateList = new ArrayList<>();
        for (BoDoor door : doors) {
            JSONObject deviceObj = topLevel.getJSONObject(door.getDeviceId());
            String openStr = deviceObj.getJSONObject("data").getJSONObject("sync_state").getString("REMOTE_CONTROL_1");
            String stateStr = deviceObj.getString("states");
            String lastTime = deviceObj.getString("lastTime");
            String batteryStr = deviceObj.getJSONObject("data").getString("BATTERY_QUANTITY_1");

            BoDoorWithState bds = new BoDoorWithState();
            bds.setName(door.getName());
            bds.setOpen(!openStr.isEmpty());
            bds.setOnline(stateStr.equals("online"));
            bds.setBatteryPower(batteryStr.equals("1.00"));
            bds.setLastOnlineTime(lastTime);
            bds.setDoorId(door.getId());

            doorStateList.add(bds);
        }

        List<BoSwitchWithState> switchStateList = new ArrayList<>();
        for (BoSwitch bs : switches) {
            JSONObject deviceObj = topLevel.getJSONObject(bs.getDeviceId());
            String openStr = deviceObj.getJSONObject("data").getJSONObject("sync_state").getString("DEV_SWITCH_STA_1");
            String stateStr = deviceObj.getString("states");
            String lastTime = deviceObj.getString("lastTime");

            BoSwitchWithState bss =new BoSwitchWithState();
            bss.setName(bs.getName());
            bss.setOpen(!openStr.isEmpty());
            bss.setOnline(stateStr.equals("online"));
            bss.setLastOnlineTime(lastTime);
            bss.setSwitchId(bs.getId());

            switchStateList.add(bss);
        }

        return new BoAllDeviceState(doorStateList,switchStateList);
    }

    private String requestAccessToken() throws Exception {
        Map<String, Object> param = new HashMap<>();
        param.put("api_token", config.getSundrayToken());
        HttpResult httpResult = HttpUtils.postBody(config.getSundrayBaseUrl() + "/accessToken", param);
        if (httpResult.getStatusCode() != 200) {
            throw new Exception("申请新瑞token失败");
        }
        Map map = JSON.parseObject(httpResult.getResult(), Map.class);
        return map.get("accessToken").toString();
    }

    private String buildCommand(String typeId, String[] deviceIds, DeviceType deviceType, String command) {
        Status status;
        if (deviceType == DeviceType.Door) {
            status = new DoorStatus(command);
        } else {
            status = new SwitchStatus(command);
        }

        Device device = new Device();
        device.setTypeID(typeId);
        device.setDeviceIDs(deviceIds);
        device.setStatus(status);

        ControlCommand controlCommand = new ControlCommand();
        controlCommand.setAppID(config.getSundrayAppId());
        controlCommand.setRecurison(false);
        controlCommand.setDevices(new Device[]{device});

        return new Gson().toJson(controlCommand);
    }

    @Data
    static class ControlCommand {
        private int appID;
        private boolean recurison;
        private Device[] devices;
    }

    @Data
    static class Device {
        private String typeID;
        private String[] deviceIDs;
        private Status status;
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @AllArgsConstructor
    static class SwitchStatus extends Status {
        private String DEV_SWITCH_STA_1;
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @AllArgsConstructor
    static class DoorStatus extends Status {
        private String REMOTE_CONTROL_1;
    }

    static class Status {

    }

    enum DeviceType {
        Door,
        Switch
    }
}



